{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3e24704f",
   "metadata": {},
   "source": [
    "* 加载视频\n",
    "* 通过形态学识别车辆\n",
    "* 对车辆进行统计\n",
    "* 显示车辆统计信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7bfbc81a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#加载视频\n",
    "cap = cv2.VideoCapture('video.mp4')\n",
    "#创建mog对象、去背景\n",
    "mog = cv2.bgsegm.createBackgroundSubtractorMOG()\n",
    "kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))\n",
    "\n",
    "min_w = 100\n",
    "min_h = 90\n",
    "line_high = 600\n",
    "# 偏移量\n",
    "offset = 6\n",
    "cars = []\n",
    "carno = 0\n",
    "#计算外接矩形的中心点\n",
    "def center(x,y,w,h):\n",
    "    x1 = int(w / 2)\n",
    "    y1 = int(h / 2)\n",
    "    cx = int(x) + x1\n",
    "    cy = int(y) + y1\n",
    "    return cx,cy\n",
    "\n",
    "#循环读取视频帧\n",
    "while True:\n",
    "    ret,frame = cap.read()\n",
    "    if ret == True:\n",
    "        #把原始帧进行灰度化，然后去噪\n",
    "        gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)\n",
    "        #去噪\n",
    "        blur = cv2.GaussianBlur(gray,(3,3),5)\n",
    "        \n",
    "        mask = mog.apply(blur)\n",
    "        \n",
    "        #腐蚀\n",
    "        erode = cv2.erode(mask,kernel)\n",
    "        #膨胀回来\n",
    "        dialte = cv2.dilate(erode,kernel,iterations=2)\n",
    "        \n",
    "        #消除内部的小块\n",
    "        #闭运算\n",
    "        close =  cv2.morphologyEx(dialte,cv2.MORPH_CLOSE,kernel)\n",
    "        \n",
    "        #查找轮廓\n",
    "        result,contours,h = cv2.findContours(close,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)\n",
    "        \n",
    "        #画出检测线\n",
    "        cv2.line(frame,(10,line_high),(1200,line_high),(255,255,0),3)\n",
    "        \n",
    "        #画出所有检测出来的轮廓\n",
    "        for contour in contours:\n",
    "            (x,y,w,h) = cv2.boundingRect(contour)\n",
    "            #通过外接矩形的宽高大小来过滤小矩形\n",
    "            is_valid = (w>=min_w) and (h>=min_h)\n",
    "            if not is_valid:\n",
    "                continue\n",
    "            #能走到这里来的都是符合要求的矩阵，即正常的车\n",
    "            #要求坐标点都是整数\n",
    "            cv2.rectangle(frame,(int(x),int(y)),(int(x+w),int(y+h)),(0,0,255),2)\n",
    "            #把车抽象为一点，即外接矩形计算外接矩形的中心点\n",
    "            cpoint = center(x,y,w,h)\n",
    "            cars.append(cpoint)\n",
    "            cv2.circle(frame,(cpoint),5,(0,0,255),-1)\n",
    "            #判断汽车是否过检测线\n",
    "            for (x,y) in cars:\n",
    "                if y>(line_high - offset) and y < (line_high + offset):\n",
    "                    #落入了有效期间\n",
    "                    #技术加1\n",
    "                    carno += 1\n",
    "                    cars.remove((x,y))\n",
    "\n",
    "        cv2.putText(frame,'Vehicle Count:'+str(carno),(500,60),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),5)\n",
    "        cv2.imshow('video',frame)\n",
    "    key = cv2.waitKey(1)\n",
    "    if key == 27:\n",
    "        break\n",
    "        \n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73fe002f",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
